// Copyright 2009 Pigasus.
// GNU GPL v2.
// Author: John Zhang and Jordan Rupprecht.
//
// Defines the parent Thread class. All threads should be derived from this, 
// which allows them to execute in a separate process.
//
// Remember: compile using -pthread when using threads.

#ifndef THREAD_H_
#define THREAD_H_

#include <stdlib.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>

#include "common.h"

using namespace std;

const int kNullThreadType = 0;
const int kJobThreadType = 1;
const int kSendThreadType = 2;
const int kGetThreadType = 3;
const int kPollThreadType = 4;

// Base class for threads. All classes that are to execute in separate threads
// should be derived from this one.
class Thread {
  pthread_t thread;

  // Run the thread.
  static void *ThreadFunction(void *t) { 
    ((Thread*)t)->Run();
    return (void *)pthread_self(); 
  } 
  
 protected:
  // Thread ID for usage with ThreadPool.
  int id; 
  int type;

 public:
  // Constructor sets the ID.
  Thread() { }

  // Empty virtual destructor.
  virtual ~Thread() { }

  // Actual job of the thread. Must be overloaded.
  virtual void Run() { }

  // Start thread execution with specified ID.   
  int Start(int id_) {
    id = id_;

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    int tid = pthread_create(&thread, NULL, Thread::ThreadFunction,
                             (void*)this);

    pthread_attr_destroy(&attr);
    return tid;
  }
  // Start thread execution with default ID -1.
  int Start() {
    return Start(-1);
  }

  // Wait until Run() finishes doing its thing.
  int Wait() {
    return pthread_join(thread, NULL);
  }

  // Return the type ID of this thread.
  int GetType() {
    return type;
  }
};

#endif  // THREAD_H_
